import type { Next, Context } from 'koa';
import knex from '../utils/knex';
import { makeTree } from '../utils/tree';
import { generateRouters } from '../utils/clientRouter';

/**
 * @api {get} /menu/retrieve 查询菜单
 * @apiVersion 1.0.0
 * @apiDescription create by wuyanshen
 * @apiName retrieve
 * @apiGroup 菜单管理
 *
 * @apiParam {int}     name    菜单名称【必填】
 * @apiParam {String}  status  菜单状态 (0:正常 1:停用)【必填】
 *
 * @apiUse RequestHeader
 * @apiUse menuRetrieveSuccess
 * @apiUse RequestError
 */
async function retrieveAction(ctx: Context, next: Next) {
    const { name, status } = ctx.query;
    const whereObj: Record<string, any> = {};
    if (name) {
        whereObj.name = ['like', `%${name}%`];
    }
    if (status) {
        whereObj.status = status;
    }
    try {
        const res = await knex('sys_menu').where(whereObj).orderBy('sort_num', 'ASC').select();
        // 生成树形结构
        const tree = makeTree(res, 'id', 'pid', 'children');
        ctx.success(tree, '查询成功');
    } catch (e) {
        ctx.fail(500, '查询失败  ' + e);
    }
    return next();
}

/**
 * @api {post} /menu/add 新增菜单
 * @apiVersion 1.0.0
 * @apiDescription create by wuyanshen
 * @apiName add
 * @apiGroup 菜单管理
 *
 * @apiParam {String}  name       菜单名称【必填】
 * @apiParam {String}  path       路由地址【必填】
 * @apiParam {String}  component  组件路径【必填】
 * @apiParam {int}     pid        父菜单id【必填】
 * @apiParam {String}  permission 按钮权限【必填】
 * @apiParam {String}  icon       菜单图标【必填】
 * @apiParam {int}     visible    是否显示 1是 0否【必填】
 * @apiParam {int}     is_cache   是否缓存 1是 0否【必填】
 * @apiParam {int}     is_frame   是否为外链 1是 0否【必填】
 * @apiParam {int}     type       类型：1菜单 2按钮 3目录【必填】
 * @apiParam {String}  status     菜单状态 (0:正常 1:停用)【必填】
 *
 * @apiUse RequestHeader
 * @apiUse addSuccess
 * @apiUse RequestError
 */
async function addAction(ctx: Context, next: Next) {
    const { name = '', path = '', pid, permission, component, icon = '', visible, is_cache, is_frame, type, status } = ctx.request.body;
    try {
        await knex('sys_menu').insert({
            name: name,
            path: path,
            pid: pid,
            permission: permission,
            component: component,
            icon: icon,
            visible: visible,
            is_cache,
            is_frame,
            type: type,
            status: status,
        });
        ctx.success('', '新增成功');
    } catch (e) {
        ctx.fail(500, '新增失败  ' + e);
    }
    return next();
}

/**
 * @api {put} /menu/update 修改菜单
 * @apiVersion 1.0.0
 * @apiDescription create by wuyanshen
 * @apiName update
 * @apiGroup 菜单管理
 *
 * @apiParam {int}     id         菜单id【必填】
 * @apiParam {String}  name       菜单名称【必填】
 * @apiParam {String}  path       路由地址【必填】
 * @apiParam {String}  component  组件路径【必填】
 * @apiParam {int}     pid        父菜单id【必填】
 * @apiParam {String}  permission 按钮权限【必填】
 * @apiParam {String}  icon       菜单图标【必填】
 * @apiParam {int}     visible    是否显示 1是 0否【必填】
 * @apiParam {int}     is_cache   是否缓存 1是 0否【必填】
 * @apiParam {int}     is_frame   是否为外链 1是 0否【必填】
 * @apiParam {int}     type       类型：1菜单 2按钮 3目录【必填】
 * @apiParam {String}  status     菜单状态 (0:正常 1:停用)【必填】
 *
 * @apiUse RequestHeader
 * @apiUse addSuccess
 * @apiUse RequestError
 */
async function updateAction(ctx: Context, next: Next) {
    const { id, name = '', path = '', pid, permission, component, icon = '', visible, is_cache, is_frame, type, status, sort_num } = ctx.request.body;
    try {
        await knex('sys_menu')
            .where({
                id: id,
            })
            .update({
                name,
                path,
                pid,
                permission,
                component,
                icon,
                visible,
                is_cache,
                is_frame,
                type,
                sort_num,
                status,
            });
        ctx.success('', '修改成功');
    } catch (e) {
        ctx.fail(500, '修改失败  ' + e);
    }
    return next();
}

/**
 * @api {delete} /menu/delete 删除菜单
 * @apiVersion 1.0.0
 * @apiDescription create by wuyanshen
 * @apiName delete
 * @apiGroup 菜单管理
 *
 * @apiParam {int} id 菜单id【必填】
 *
 * @apiUse RequestHeader
 * @apiUse deleteSuccess
 * @apiUse RequestError
 */
async function deleteAction(ctx: Context, next: Next) {
    const id = ctx.query.id;
    try {
        const res = await knex('sys_menu').where({ pid: id }).select();
        if (res && Array.isArray(res) && res.length > 0) {
            ctx.fail(400, '存在子菜单不允许删除');
            return next();
        }
        await knex('sys_menu').where({ id: id }).delete();
        ctx.success('', '删除成功');
    } catch (e) {
        ctx.fail(500, '删除失败  ' + e);
    }
    return next();
}

/**
 * @api {get} /menu/all 查询所有菜单
 * @apiVersion 1.0.0
 * @apiDescription create by wuyanshen
 * @apiName all
 * @apiGroup 菜单管理
 *
 * @apiUse RequestHeader
 * @apiUse menuAllSuccess
 * @apiUse RequestError
 */
async function allAction(ctx: Context, next: Next) {
    try {
        const res = await knex('sys_menu').orderByRaw('sort_num ASC').select();
        // 生成树形结构
        const tree = makeTree(res, 'id', 'pid', 'children');
        ctx.success(tree, '查询成功');
    } catch (e) {
        ctx.fail(500, '查询失败  ' + e);
    }
    return next();
}

/**
 * @api {get} /menu/tree 查询当前用户的菜单
 * @apiVersion 1.0.0
 * @apiDescription create by wuyanshen
 * @apiName tree
 * @apiGroup 菜单管理
 *
 * @apiUse RequestHeader
 * @apiUse menuTreeSuccess
 * @apiUse RequestError
 */
async function treeAction(ctx: Context, next: Next) {
    /**
     *
     select m.* from sys_menu m
     left join sys_role_menu rm on m.id = rm.menu_id
     left join sys_user_role ur on ur.role_id = rm.role_id
     left join sys_user u on u.id = ur.user_id
     where u.id = 1;
     */
    const userId = ctx.user.id;
    const menus = await knex({ m: 'sys_menu' })
        .leftJoin({ rm: 'sys_role_menu' }, 'rm.menu_id', 'm.id')
        .leftJoin({ ur: 'sys_user_role' }, 'ur.role_id', 'rm.role_id')
        .leftJoin({ u: 'sys_user' }, 'u.id', 'ur.user_id')
        .columns('m.*')
        .where({ 'u.id': userId, 'm.status': '0' })
        .andWhere('m.type', '<>', 2)
        .orderByRaw('m.sort_num ASC')
        .select();

    // 菜单去重
    const menuIds = menus.map((menu) => menu.id);
    const res = menus.filter((item, index) => {
        const one = menuIds.indexOf(item.id) === index;
        return one;
    });

    // 生成树形结构
    const tree = makeTree(res, 'id', 'pid', 'children');
    // 生成vue前端路由结构
    const routers = generateRouters(tree);
    ctx.success(routers);
    return next();
}

const menuController = {
    retrieveAction,
    addAction,
    updateAction,
    deleteAction,
    allAction,
    treeAction,
};

export default menuController;
